home *** CD-ROM | disk | FTP | other *** search
- NAME ccscmd
- ; File CCSCMD.ASM
-
- ;CHINESE
- ifdef MSDOS
- include msscmd.dat
- else
- include ccscmd.dat
- endif
-
- code segment public 'code'
- extrn ctlu:near, cmblnk:near, clearl:near, locate:near, takrd:near
- extrn takclos:near, docom:near
- assume cs:code, ds:datas, es:nothing
-
- ; This routine parses the specified function in AH. Any additional
- ; information is in DX and BX.
- ; Returns rskp on success and ret on failure
-
- COMND PROC NEAR
- mov cmdstk,sp ; save stack ptr for longjmp exit
- mov noparse,0 ; recognize semicolons in Take files
- cmp ah,cmcfm ; Parse a confirm?
- jne cm2 ; nz = no
- jmp cmcfrm ; get a confirm
- cm2: cmp ah,cmkey ; Parse a keyword?
- jne cm3
- jmp cmkeyw ; Try and get one
- cm3: cmp ah,cmtxt ; Parse arbitrary text
- jne cm4
- jmp cmtext
- cm4: cmp ah,cmfile ; parse text surrounded by whitespace
- jne cm5
- jmp cmfil0
- cm5: mov ah,prstr ; Else give error
- ; mov dx,offset cmer00 ; "?Program internal error"
- mcmsg cmer00,ccmer00
-
- int dos
- jmp prserr
- COMND ENDP
-
- ; This routine parses a keyword from the table pointed at by DX, help text
- ; point to by BX. Format of the table is as follows (use macro mkeyw):
- ; addr: db N ; Where N is the # of entries in the table
- ; db M ; M is the size of the keyword (excl '$')
- ; db 'string$' ; String is the keyword
- ; dw value ; Value is data to be returned
- ; Keywords may be in any order and in mixed case.
- ; Return is rskp for success and ret for failure.
-
- ; comand.cmptab: pointer to keyword table (supplied by caller)
- ; comand.cmhlp: pointer to help message (supplied by caller)
- ; comand.cmsptr: pointer to current user word text
- ; comand.cmsiz: length of user text, excluding terminator
- ; comand.cmcr: 0 = empty lines not allowed, 1 = empty lines allowed
- ; comand.cmwhite: non-zero allows leading whitespace for cmtxt and cmfile,
- ; reset automatically at end of call
- ; comand.cmwptr: buffer write pointer to next free byte
- ; comand.cmrptr: buffer read pointer for next free byte
- ; comand.cmper: 0 to do \%x substitution. Set to 0 at end of call
- ; comand.impdo: non-zero permits keyword failure to retry as DO command, reset
- ; automatically at time of failure.
- cmkeyw proc near
- mov comand.cmsiz,0 ; user word length
- mov ax,comand.cmrptr ; get command reading pointer
- mov comand.cmsptr,ax ; set pointer for start of user word
- mov comand.cmhlp,bx ; save the help pointer
- mov comand.cmptab,dx ; save the beginning of keyword table
- mov bx,dx
- cmp byte ptr[bx],0 ; get number of entries in table
- jne cmky1
- jmp cmky7 ; e = no keywords to check, error
- cmky1: mov comand.cmsflg,0ffh ; skip leading spaces/tabs
- call cmgtch ; get char from the user into ah
- jc cmky3 ; c = terminator
- mov dx,comand.cmrptr ; next byte to read
- dec dx ; where we just read a char
- mov comand.cmsptr,dx ; remember start of keyword
- inc comand.cmsiz ; start counting user chars
- cmky2: call cmgtch ; read until terminator
- jc cmky3 ; c = terminator
- inc comand.cmsiz ; count user chars
- jmp short cmky2 ; no terminator yet
-
- cmky3: cmp ah,'?' ; need help?
- jne cmky4 ; ne = no
- jmp cmkyhlp ; do help and exit
- cmky4: cmp ah,escape ; escape?
- jne cmky6 ; ne = no
- call cmkyesc ; process escape
- jc cmky5 ; c = failure (no unique keyword yet)
- mov comand.cmper,0 ; reset to variable recognition
- mov comand.cmkeep,0
- mov comand.impdo,0 ; clear flag to prevent loops
- mov comand.cmquiet,0 ; permit echoing again
- jmp rskp ; return successfully to user
-
- cmky5: cmp comand.cmsiz,0 ; started a word yet?
- je cmky1 ; e = no, ignore escape, keep looking
- jmp cmkyhlp ; ne = yes, show type of error
-
- cmky6: cmp comand.cmsiz,0 ; length of user's text, empty?
- je cmky7 ; e = yes, parse error
- push bx
- mov bx,comand.cmsptr ; point at first user character
- cmp byte ptr[bx],':' ; start of a label?
- pop bx
- jne cmky6a ; ne = no, return success
- mov comand.cmsiz,1 ; say just one byte
- cmky6a:
- call getkw ; get unique kw, point to it with bx
- jc cmky8 ; c = not found
- add bl,[bx] ; add length of keyword text (CNT)
- adc bh,0
- add bx,2 ; point at value field
- mov bx,[bx] ; bx = return value following keyword
- mov comand.cmper,0 ; reset to variable recognition
- mov comand.cmkeep,0
- mov comand.impdo,0 ; clear flag to prevent loops
- mov comand.cmquiet,0 ; permit echoing again
- mov errflag,0
- jmp rskp ; return successfully
- ; all other terminators come here
- cmky7: cmp comand.cmsiz,0 ; empty table or empty user's text?
- jne cmky8 ; ne = no
- cmp comand.cmcr,0 ; empty lines allowed?
- jne cmky10 ; ne = yes, do not complain
- push dx
- mov ah,prstr
- ; mov dx,offset cmer01 ; command word expected
- mcmsg cmer01,ccmer01
-
- int dos
- pop dx
- mov comand.cmquiet,0 ; permit echoing again
- mov comand.impdo,0 ; clear flag to prevent loops
- ret ; do ret exit
-
- cmky8: cmp comand.impdo,0 ; failed here, ok to try Macro table?
- je cmky8a ; e = no, use regular exit path
- mov comand.impdo,0 ; yes, but clear flag to prevent loops
- mov comand.cmrptr,offset comand.cmdbuf ; reinit read pointer
- mov comand.cmquiet,1 ; suppress echoing of same keyword
- mov bx,offset docom ; return DO as "found" keyword
- jmp rskp ; return success to invoke DO
-
- cmky8a: mov comand.cmquiet,0 ; permit echoing again
- mov errflag,1 ; say already doing error recovery
- or kstatus,1 ; global command status, failure
- call isdev ; reading pretyped lines?
- jnc cmky9 ; nc = yes, consume rest of line
- cmp taklev,0 ; in a Take file?
- jne cmky9 ; ne = yes
- call cmskw ; display offending keyword
- dec comand.cmrptr ; interactive, backup to terminator
- mov bx,comand.cmrptr ; look at it
- cmp byte ptr [bx],' ' ; got here on space terminator?
- jne cmky10 ; ne = no, (cr,lf,ff) exit failure
- mov ah,prstr ; start a fresh line
- mov dx,offset crlf
- int dos
- call bufreset ; cut back buffer to just before term
- jmp repars ; reparse interactive lines
-
- cmky9: call cmcfrm ; get formal end of command line
- nop ; to maintain illusion of typeahead
- nop ; and let user backspace to correct
- nop ; mistakes (we reparse everything)
- call cmskw ; display offending keyword
- cmky10: ret ; do ret exit
- cmkeyw endp
-
- ;;;;;; start support routines for keyword parsing.
-
- cmkyesc proc near ; deal with escape terminator
- call bufreset ; reset buffer to end just before ESC
- cmp comand.cmsiz,0 ; user word length, empty?
- jne cmkye2 ; ne = have user text, else complain
- cmkye1: call esceoc ; do normal escape end-of-command
- stc ; say failure to fill out word
- ret
- ; add unique keyword to buffer
- cmkye2: call getkw ; is there a matching keyword?
- jc cmkye1 ; c = ambiguous or not found
- push bx ; unique, bx points to structure
- push si
- mov cl,[bx] ; length of keyword
- mov ch,0
- inc bx ; point to first letter
- mov si,comand.cmwptr ; where next char goes
- mov dx,comand.cmsiz ; length of user word
- add bx,dx ; add chars known so far
- sub cx,dx ; calculate number yet to add
- add comand.cmsiz,cx
- jcxz cmkye4 ; z = none
- mov ah,conout ; display new char
- cmkye3: mov al,[bx] ; get a keyword letter
- inc bx
- call tolowr ; lowercase
- mov [si],al ; store it
- inc si
- mov dl,al
- int dos ; display it
- loop cmkye3 ; do all new chars
- cmkye4: mov byte ptr[si],' ' ; insert space terminator in buffer
- mov dl,' ' ; display it
- mov ah,conout
- int dos
- inc si
- mov comand.cmrptr,si ; move token pointer after the space
- mov comand.cmwptr,si ; next free slot is after the space
- mov comand.cmsflg,0ffh ; set space-seen flag
- pop si
- pop bx ; bx = keyword structure
- add bl,[bx] ; add length of keyword text
- adc bh,0
- add bx,2 ; point at value field
- mov bx,[bx] ; bx = return value following keyword
- clc ; carry clear for success
- ret
- cmkyesc endp
-
- esceoc proc near ; do normal escape end-of-command
- push ax
- push dx
- mov ah,conout ; ring the bell
- mov dl,bell
- int dos
- pop dx
- pop ax
- call bufreset ; reset buffer
- stc ; say error condition
- ret
- esceoc endp
-
- ; Help. Question mark entered by user. Display all the keywords that match
- ; user text. If text is null then use external help if available; otherwise,
- ; display all keywords in the table. Removes question mark from buffer and
- ; invokes reparse of command line to-date. User word starts at .cmsptr and
- ; is .cmsiz bytes long.
- cmkyhlp proc near
- mov cx,0 ; clear number of keyword (none yet)
- cmp comand.cmsiz,0 ; user text given?
- jne cmkyh1 ; ne = yes, use matching keywords
- cmp comand.cmhlp,0 ; external help given?
- jne cmkyh6 ; yes, use it instead of full table
- cmkyh1: mov temp,0 ; count # chars printed on this line
- mov bx,comand.cmptab ; beginning of kw table
- mov ch,[bx] ; length of table
- mov cl,0 ; no keywords or help displayed yet
- inc bx ; point at CNT field
- cmkyh2: cmp comand.cmsiz,0 ; length of user word
- je cmkyh3 ; e = null, use full table
- call cmpwrd ; compare keyword with user word
- jc cmkyh5 ; c = no match, get another keyword
- cmkyh3: mov al,[bx] ; length of table keyword
- add byte ptr temp,al ; count chars printed so far
- cmp temp,76 ; will this take us beyond column 78?
- jbe cmkyh4 ; be = no, line has more room
- mov ah,prstr
- mov dx,offset crlf ; break the line
- int dos
- mov temp,0 ; and reset the count
- cmkyh4: cmp cl,0 ; any keywords found yet?
- jne cmkyh4a ; ne = yes
- ; mov dx,offset cmin01 ; start with One of the following: msg
- mcmsg cmin01,ccmin01
- mov ah,prstr
- int dos
- inc cl ; say one keyword has been found
- cmkyh4a:mov dl,spc ; put two spaces before each keyword
- mov ah,conout
- int dos
- int dos
- add temp,2 ; count output chars
- mov dx,bx ; get current keyword structure
- inc dx ; text part
- mov ah,prstr
- int dos ; display it
- cmkyh5: dec ch ; are we at end of table?
- jle cmkyh7 ; le = yes, quit now
- add bl,[bx] ; next keyword, add CNT chars to bx
- adc bh,0
- add bx,4 ; skip CNT, '$' and 16 bit value
- jmp cmkyh2 ; go examine this keyword
-
- cmkyh6: mov dx,comand.cmhlp ; external help text
- mov ah,prstr
- int dos
- inc cl ; say gave help already
- cmkyh7: cmp cl,0 ; found any keywords?
- jne cmkyh9 ; ne = yes
- mov cx,comand.cmsiz ; length of word
- cmp cx,0
- jg cmkyh8 ; g = something to show
- push dx
- mov ah,prstr
- ; mov dx,offset cmer01 ; command word expected
- mcmsg cmer01,ccmer01
-
- int dos
- pop dx
- jmp prserr
- cmkyh8: mov kwstat,0 ; set keyword not-found status
- call cmskw ; display offending keyword
- cmkyh9: mov ah,prstr ; start a fresh line
- mov dx,offset crlf
- int dos
- call bufreset ; cut back buffer to just before '?'
- jmp repars
- cmkyhlp endp
-
- ; See if keyword is ambiguous or not from what the user has typed in.
- ; Return carry set if word is ambiguous or not found, carry clear otherwise.
- ; Uses table pointed at by comand.cmptab, user text pointed at by
- ; comand.cmsptr and length in comand.cmsiz.
- cmambg proc near
- push bx
- push cx
- push dx
- mov dl,0 ; count keyword matches so far
- mov bx,comand.cmptab ; look at start of keyword table
- mov cl,[bx] ; get number of entries in table
- mov ch,0 ; use cx as a counter
- jcxz cmamb8 ; z = no table so always ambiguous
- inc bx ; look at CNT byte of keyword
- cmamb4: call cmpwrd ; user vs table words, same?
- jc cmamb6 ; c = no match
- inc dl ; count this as a match
- cmp dl,1 ; more than one match?
- ja cmamb8 ; a = yes, quit now
- cmamb6: add bl,[bx] ; add CNT chars to bx
- adc bh,0
- add bx,4 ; skip CNT, '$' and 16 bit value
- loop cmamb4 ; do rest of keyword table
- cmamb7: cmp dl,1 ; how many matches were found?
- jne cmamb8 ; ne = none or more than 1: ambiguous
- pop dx ; restore main registers
- pop cx
- pop bx
- clc
- ret ; ret = not ambiguous
- cmamb8: pop dx ; restore main registers
- pop cx
- pop bx
- stc
- ret ; return ambiguous or not found
- cmambg endp
-
- ; Compare user text with keyword, abbreviations are considered a match.
- ; Enter with bx pointing at keyword table CNT field for a keyword.
- ; Return carry clear if they match, set if they do not match. User text
- ; pointed at by comand.cmsptr and length is in comand.cmsiz.
- ; Registers preserved.
-
- cmpwrd proc near
- push cx
- mov cx,comand.cmsiz ; length of user's text
- jcxz cmpwrd2 ; z: null user word matches no keyword
- cmp cl,[bx] ; user's text longer than keyword?
- ja cmpwrd2 ; a = yes, no match
- push ax
- push bx
- push si
- inc bx ; point at table's keyword text
- mov si,comand.cmsptr ; buffer ptr to user input
- cld
- cmpwrd1:lodsb ; user text
- mov ah,[bx] ; keyword text
- inc bx ; next keyword letter
- call tolowr ; force lower case on both chars
- cmp ah,al ; same?
- loope cmpwrd1 ; e = same so far
- pop si
- pop bx
- pop ax
- jne cmpwrd2 ; ne = mismatch
- pop cx ; recover keyword counter
- clc ; they match
- ret
- cmpwrd2:pop cx ; recover keyword counter
- stc ; they do not match
- ret
- cmpwrd endp
-
- ; Get pointer to keyword structure using user text. Uses keyword table
- ; pointed at by comand.cmptab and comand.cmsiz holding length
- ; of user's keyword (cmpwrd needs comand.cmsptr pointing at user's
- ; keyword and length of comand.cmsiz). Structure pointer returned in BX.
- ; Return carry clear for success and carry set for failure. Modifies BX.
- getkw proc near
- push cx
- mov kwstat,0 ; keyword status, set to not-found
- cmp comand.cmsiz,0 ; length of user word, empty?
- je getkw3 ; e = yes, fail
- mov bx,comand.cmptab ; table of keywords
- mov cl,[bx] ; number of keywords in table
- mov ch,0
- jcxz getkw3 ; z = none, fail
- inc bx ; point to first
- getkw1: call cmpwrd ; compare user vs table words
- jc getkw2 ; c = failed to match word, try next
- mov kwstat,1 ; say found one keyword, maybe more
- push dx
- mov dx,comand.cmsiz ; users word length
- cmp [bx],dl ; same length (end of keyword)?
- pop dx
- je getkw4 ; e = yes, exact match. Done
- call cmambg ; ambiguous?
- jnc getkw4 ; nc = unique, done, return with bx
- mov kwstat,2 ; say more than one such keyword
- getkw2: add bl,[bx] ; next keyword, add CNT chars to bx
- adc bh,0
- add bx,4 ; skip CNT, '$' and 16 bit value
- loop getkw1 ; do all, exhaustion = failure
- getkw3: pop cx
- stc ; return failure
- ret
- getkw4: pop cx
- clc ; return success
- ret
- getkw endp
-
- ; show offending keyword message. Comand.cmsptr points to user word,
- ; comand.cmsiz has length. Modifies AX, CX, and DX.
- cmskw proc near
- mov ah,prstr ; not one of the above terminators
- ; mov dx,offset cmer02 ; '?Word "'
- mcmsg cmer02,ccmer02
-
- int dos
- mov cx,comand.cmsiz ; length of word
- jcxz cmskw3 ; z = null
- mov ah,conout
- push si
- mov si,comand.cmsptr ; point to word
- cld
- cmskw1: lodsb
- cmp al,' ' ; control code?
- jae cmskw2 ; ae = no
- push ax
- mov dl,5eh ; caret
- int dos
- pop ax
- add al,'A'-1 ; plus ascii bias
- cmskw2: mov dl,al ; display chars in word
- int dos
- loop cmskw1
- pop si
- cmskw3:
- ; mov dx,offset cmer03 ; '" not usable here.'
- mcmsg cmer03,ccmer03
-
- cmp kwstat,1 ; kywd status from getkw, not found?
- jb cmskw4 ; b = not found, a = ambiguous
- ; mov dx,offset cmer04 ; '" ambiguous'
- mcmsg cmer04,ccmer04
-
- cmskw4: mov ah,prstr
- int dos
- ret
- cmskw endp
- ;;;;;;;;;; end of support routines for keyword parsing.
-
- ; Parse arbitrary text up to a CR. Enter with BX = pointer to output buffer,
- ; DX pointing to help text. Produces asciiz string. Return updated pointer in
- ; BX and output size in AH. Leading spaces are omitted unless comand.cmwhite
- ; is non-zero (cleared upon exit). It does not need to be followed by the
- ; usual call to confirm the line. Byte comand.cmblen can be used to specify
- ; the length of the caller's buffer; cleared to zero by this command to
- ; imply a length of 127 bytes (default) and if zero at startup use 127 bytes.
- cmtext proc near
- mov comand.cmptab,bx ; save pointer to data buffer
- mov comand.cmhlp,dx ; save the help message
- mov cx,0 ; init the char count
- cmp comand.cmblen,0 ; length of user's buffer given?
- jne cmtxt0 ; ne = yes
- mov comand.cmblen,127 ; else set 127 byte limit plus null
- cmtxt0: mov comand.cmsflg,0ffh ; skip initial spaces
- cmp comand.cmwhite,0 ; allow leading whitespace?
- je cmtxt1a ; e = no
- cmtxt1: mov comand.cmsflg,0 ; get all spaces
- cmtxt1a:call cmgtch ; get a char
- jnc cmtxt5 ; nc = non-terminator, put in buffer
- cmp ah,' ' ; space?
- je cmtxt5 ; e = yes, record it
- cmp ah,escape ; escape?
- jne cmtxt2 ; ne = no
- call esceoc ; do normal escape end-of-command
- jmp cmtxt0 ; try again
-
- cmtxt2: cmp ah,'?' ; asking a question?
- je cmtxt3 ; e = yes
- cmp ah,cr ; formal carriage return?
- je cmtxt2a ; e = yes
- inc comand.cmrptr ; accept char into buffer
- jmp cmtxt5 ; and record the char
- cmtxt2a:mov ah,cl ; return count in AH
- mov bx,comand.cmptab ; return updated pointer
- mov byte ptr[bx],0 ; put terminator into the buffer
- mov comand.cmwhite,0 ; clear leading whitespace flag
- mov comand.cmper,0 ; reset to variable recognition
- mov comand.cmblen,0 ; set user buffer length to unknown
- mov comand.cmkeep,0
- jmp rskp
- ; Help processor
- cmtxt3: inc comand.cmrptr ; count the ?
- cmp cx,0 ; Is "?" first char?
- jne cmtxt5 ; ne = no, just add to buffer
- dec comand.cmrptr
- mov comand.cmsiz,0 ; no keyword for help
- mov comand.cmwhite,0 ; clear leading whitespace flag
- cmp comand.cmhlp,0 ; external help given?
- jne cmtxt3a ; ne = yes
- ;---------------------- Sept.20,1990 [zqf]
- ; mov comand.cmhlp,offset cmin00 ; confirm with c/r msg
- push dx
- mcmsg cmin00,ccmin00
- mov comand.cmhlp,dx
- pop dx
- ;----------------------
- mov comand.cmblen,0 ; set user buf length to unknown
- cmtxt3a:jmp cmkyhlp ; do help process
-
- cmtxt5: inc cx ; increment the count
- mov bx,comand.cmptab ; pointer into destination array
- mov [bx],ah ; put char into the buffer
- inc bx
- mov al,0
- mov [bx],al ; insert null terminator
- mov comand.cmptab,bx
- cmp ch,0 ; overflowed into high byte?
- jne cmtxt6 ; ne = yes
- cmp cl,comand.cmblen ; buffer filled?
- ja cmtxt6 ; a = yes, declare error
- jb cmtxt5a ; a = not filled yet
- mov ah,conout ; notify user that the buffer is full
- mov dl,bell
- int dos
- cmtxt5a:jmp cmtxt1
- cmtxt6: mov ah,prstr
- ; mov dx,offset cmer09
- mcmsg cmer09,ccmer09
-
- int dos
- jmp prserr ; declare parse error
- cmtext endp
-
-
- ; Parse arbitrary text up to whitespace. Enter with DX pointing to output
- ; buffer and BX pointing to help text. Produces asciiz string. Return updated
- ; pointer in DX and input size in AH. Skips leading whitespace unless
- ; comand.cmwhite is non-zero (cleared upon exit). Does a return skip exit.
-
- cmfil0 proc near
- mov comand.cmptab,dx ; save pointer to data buffer
- mov comand.cmhlp,bx ; save the help message
- mov comand.cmsiz,0 ; init the char count
- cmfil0a:cmp comand.cmwhite,0 ; allow leading whitespace?
- jne cmfil1 ; ne = yes
- mov comand.cmsflg,0ffh ; omit leading space
- cmfil1: call cmgtch ; get a char
- jc cmfi1a ; c = terminator
- jmp cmfil5 ; put char into the buffer
- cmfi1a: cmp ah,escape ; escape?
- je cmfi1b ; e = yes
- jmp cmfil2 ; process other terminators
-
- cmfi1b: call esceoc ; do normal escape end-of-command
- jmp cmfil0a ; try again
- cmfil2: cmp ah,'?' ; asking a question?
- je cmfil3 ; e = yes
- xchg dx,bx ; re-interchange bx and dx
- mov comand.cmwhite,0 ; clear whitespace flag
- mov comand.cmper,0 ; reset to variable recognition
- mov comand.cmkeep,0
- mov bx,comand.cmptab ; pointer into destination array
- mov byte ptr[bx],0 ; put null terminator into the buffer
- inc bx
- mov ah,byte ptr comand.cmsiz ; return count in AH
- mov dx,comand.cmptab ; return updated pointer
- xchg dx,bx ; re-interchange bx and dx
- mov comand.cmwhite,0 ; clear whitespace flag
- mov comand.cmper,0 ; reset to variable recognition
- mov comand.cmkeep,0
- jmp rskp ; return success
-
- cmfil3: inc comand.cmrptr ; count the ?
- cmp comand.cmsiz,0 ; Is "?" first char?
- jne cmfil5 ; ne = no, just add to buffer
- dec comand.cmrptr
- mov comand.cmsiz,0
- cmp comand.cmhlp,0 ; external help given?
- jne cmfil3a ; ne = yes
- ; ------------------------Sept.20,1990 [zqf]
- ; mov comand.cmhlp,offset cmin00 ; confirm with c/r msg
- push dx
- mcmsg cmin00,ccmin00
- mov comand.cmhlp,dx
- pop dx
- ; ------------------------
- cmfil3a:jmp cmkyhlp ; do help process
-
- cmfil5: inc comand.cmsiz ; inrement the count
- mov bx,comand.cmptab ; pointer into destination array
- mov [bx],ah ; put char into the buffer
- inc bx
- mov comand.cmptab,bx
- jmp cmfil1 ; the end of cmfil0
- cmfil0 endp
-
- ; This routine gets a confirm (CR) and displays any extra non-blank text.
- ; errflag non-zero means suppress "extra text" display in this routine
- ; because another routine is handling errors.
- cmcfrm proc near
- mov comand.cmper,1 ; do not react to \%x substitutions
- cmcfr1: mov comand.cmsflg,0ffh ; set space-seen flag (skip spaces)
- call cmgtch ; get a char
- push comand.cmrptr
- pop temp ; remember first non-space position
- jc cmcfr4 ; c = terminator
- dec temp ; backup to text char
- cmcfr3: mov comand.cmsflg,0ffh ; set space-seen flag (skip spaces)
- call cmgtch
- jnc cmcfr3 ; read until terminator
- cmcfr4: cmp ah,' '
- je cmcfr3 ; ignore ending on space
- cmp ah,escape ; escape?
- jne cmcfr5 ; ne = no
- call esceoc ; do standard end of cmd on escape
- mov ax,comand.cmrptr
- cmp ax,temp ; started text yet?
- je cmcfr1 ; e = no
- jmp short cmcfr3 ; try again
- cmcfr5: cmp ah,'?' ; curious?
- jne cmcfr6 ; ne = no
- ;---------------------- Sept.20,1990 [zqf]
- ; mov comand.cmhlp,offset cmin00 ; msg Confirm with c/r
- push dx
- mcmsg cmin00,ccmin00
- mov comand.cmhlp,dx
- pop dx
- ;----------------------
- mov comand.cmsiz,0 ; no keyword
- mov errflag,0
- jmp cmkyhlp ; do help
- cmcfr6: cmp ah,cr ; the confirmation char?
- jne cmcfr3 ; ne = no
- cmp errflag,0 ; already doing one error?
- jne cmcfr7 ; ne = yes, skip this one
- mov cx,comand.cmrptr ; pointer to terminator
- mov dx,temp ; starting place
- sub cx,dx ; end minus starting point = length
- cmp cx,0 ; string present?
- jle cmcfr7 ; le = nothing to display
- push dx ; save source pointer
- mov ah,prstr
- ; mov dx,offset cmer07 ; ?Ignoring extras
- mcmsg cmer07,ccmer07
-
- int dos
- pop dx
- mov bx,1 ; stdout handle, cx=count, dx=src ptr
- mov ah,write2 ; allow embedded dollar signs
- int dos
- mov ah,prstr
- mov dx,offset cmer08 ; trailer msg
- int dos
- cmcfr7: mov errflag,0
- mov comand.cmper,0 ; reset to variable recognition
- mov comand.cmkeep,0
- jmp rskp ; return confirmed
- cmcfrm endp
-
- ;;; Routines to get and edit incoming text.
-
- ; Detect '\%x' (x = '0' or above) and substitute the matching Macro string
- ; in place of the '\%x' phrase in the user's buffer. If comand.cmper != 0
- ; then treat '\%' as literal characters. If no matching parameter exists
- ; just remove '\%x'. Returns carry clear if nothing done, else carry set and
- ; new text already placed in user's buffer. comand.cmwptr and comand.cmcnt
- ; are updated. Uses depth-first recursion algorithm. All registers preserved.
- subst proc near
- cmp comand.cmper,0 ; should we recognize '\%'?
- jne subst2 ; ne = no, treat as literals
- cmp ah,'\' ; is it the first char of the pattern?
- jne subst1 ; ne = no, try next
- mov subcnt,1 ; say first is matched
- jmp short subst2 ; exit successfully
- subst1: cmp subcnt,1 ; first char matched already?
- ja subst3 ; a = first two have been matched
- jb subst2 ; b = none yet
- inc subcnt ; assume a match follows
- cmp ah,'%' ; second match char, same?
- je subst2 ; e = yes
- mov subcnt,0 ; mismatch, clear match counter
- subst2: clc ; carry clear = no substitution done
- ret
- subst3: mov subcnt,0 ; clear match counter
- cmp ah,'0' ; third char is '0' or above?
- jb subst2 ; b = out of range, no match
- push bx ; save working regs
- push cx
- sub comand.cmrptr,3 ; reread commands where backslash was
- call bufreset ; reset buffer to this point
- push comand.cmptab ; save current keyword parsing parms
- push comand.cmsptr
- push comand.cmsiz
- mov bx,comand.cmrptr ; points at backslash
- mov comand.cmsptr,bx ; direct keyword routine to it
- mov comand.cmsiz,3 ; three bytes (\%x) of user text
- mov comand.cmptab,offset mcctab ; use Macro table for new text
- call getkw ; get ptr, bx, to matching keyword
- pop comand.cmsiz ; restore borrowed keyword parameters
- pop comand.cmsptr
- pop comand.cmptab
- jc substx ; c = not found, keep after pops
- mov cl,byte ptr[bx] ; length of found word
- add cl,2 ; plus count field and '$'
- mov ch,0
- add bx,cx ; point to 16 bit value (string ptr)
- mov bx,[bx] ; point to string structure
- mov cl,[bx] ; length of string (ch=0 from above)
- inc bx ; skip length byte, bx=string address
- jcxz substx ; z = nothing left to transfer
- cld
- subst4: mov ah,[bx] ; get a char
- inc bx
- push di ; assume di is used by other routines
- mov di,comand.cmrptr
- mov [di],ah ; store char (without es:di)
- inc di
- mov comand.cmwptr,di ; where to store next char
- mov comand.cmrptr,di ; move read pointer too
- cmp di,offset comand.cmdbuf+size cmdbuf ; reached max buffer size?
- pop di
- jae subst6 ; ae = yes, no more room
- cmp sp,20*2 ; still some stack space?
- jle subst6 ; le = insufficient room
- call SUBST ; rescan what we stored (recursion)
- jnc subst5 ; nc = no substitution, so no kbd test
- push ax ; break out of loops with Control-C
- push dx
- mov ah,constat ; check console status for Control-C
- int dos ; our control-break handler sees it
- pop dx ; and cmgetc reads it
- pop ax
- subst5: loop subst4
- substx: pop cx
- pop bx
- stc ; set carry to say have stored chars
- ret
- subst6: mov ah,prstr
- ; mov dx,offset stkmsg ; out of work space msg
- mcmsg stkmsg,cstkmsg
-
- int dos
- jmp prserr ; and declare parse error
- subst endp
-
- ; Read chars from Take file, keyboard, or redirected stdin. Edit and remove
- ; BS & DEL, Tab becomes space, act on Control-C, pass Control-U and Control-W.
- ; Do echoing unless comand.cmquiet is non-zero. Do semicolon comments in Take
- ; and indirect stdin files (\; means literal semicolon). Return char in AL.
- CMGETC proc near ; Basic raw character reader
- mov ah,taklev ; get current Take level
- mov intake,ah ; remember here for later callers
- cmget01:cmp prevch,0 ; left over char yet to be exported?
- je cmget02 ; e = no
- mov al,prevch ; get old char
- mov prevch,0 ; clear storage
- jmp cmget6 ; analyze it
- cmget02:cmp taklev,0 ; in a Take file?
- jne cmget1 ; ne = yes, do Take reader section
- call isdev ; is stdin a device or a file?
- jnc cmget20 ; nc = file (redirection of stdin)
- jmp cmget10 ; c = device, do separately
-
- cmget20:call iseof ; see if file is empty
- jc cmget21 ; c = EOF on disk file
- mov ah,coninq ; read the char from file, not device
- int dos
- cmp al,cr ; is it a cr?
- je cmget01 ; yes, ignore and read next char
- cmp al,ctlz ; Control-Z?
- je cmget21 ; e = yes, same as EOF here
- cmp al,lf ; LF's end lines from disk files
- jne cmget23 ; ne = not LF, pass along as is
- mov al,cr ; make LF a CR for this parser
- call iseof ; see if this is the last char in file
- jnc cmget23 ; nc = not EOF, process new CR
- cmget21:mov flags.extflg,1 ; EOF on disk file, set exit flag
- cmget23:jmp short cmget6 ; do echoing and return
-
- cmget1: push bx ; read from Take file
- mov bx,takadr
- cmp [bx].takcnt,0 ; bytes remaining in Take buffer
- jne cmget4 ; ne = not empty
- cmp [bx].taktyp,0feh ; type of Take (file?)
- jne cmget3 ; ne = no (macro)
- call takrd ; read another buffer
- cmp [bx].takcnt,0 ; anything in the file?
- jne cmget4 ; ne = yes
- cmget3: pop bx ; clear stack
- jmp cmget5 ; close take file
-
- cmget4: push si
- mov si,[bx].takptr ; read a char from Take buffer
- cld
- lodsb
- mov [bx].takptr,si ; move buffer pointer
- pop si
- dec [bx].takcnt ; decrease number of bytes remaining
- pop bx
- cmp al,ctlz ; Control-Z?
- jne cmget6 ; ne = no
- cmget5: cmp comand.cmkeep,0 ; keep Take/macro open after eof?
- jne cmget5a ; ne = yes
- call takclos ; close take file
- cmget5a:mov al,cr ; report cr as last char
- mov noparse,0 ; and say end of comment
- ; start common code
- cmget6: cmp al,lf ; line feed?
- jne cmget8 ; ne = no
- jmp cmget01 ; yes, ignore and read another char
- ; handle comments (echo but not parse)
- cmget8: cmp noparse,0 ; parsing?
- jne cmget9 ; ne = yes, do echo and no parse
- cmp prevch,0 ; have previous char to analyze?
- jne cmget8c ; ne = yes
- cmp al,'\' ; start of '\;'?
- jne cmget8a ; ne = no
- mov prevch,al ; yes, maybe. save '\' til later
- jmp cmget02 ; read next char
- cmget8a:cmp al,';' ; possible start of comment?
- jne cmget8e ; no, export al
- mov al,' ' ; replace ';' with space for comment
- jmp cmget9 ; go start a comment
-
- cmget8c:cmp al,';' ; end of '\;'?
- je cmget8d ; e = yes, omit leading backslash
- xchg prevch,al ; no, save new, recover old '\'
- jmp short cmget8e ; export '\'
- cmget8d:mov prevch,0 ; clear old '\'
- cmget8e:jmp cmget12 ; do parsing
- mov prevch,0 ; clear previous char
- jmp cmget02 ; get next char
-
- ; echo comment
- cmget9: cmp flags.takflg,0 ; echoing take files?
- je cmget9a ; e = no
- push ax
- push dx
- mov ah,conout ; echo current char
- mov dl,al
- int dos
- pop dx
- pop ax
- cmget9a:mov noparse,0 ; cr ends comment
- cmp al,cr ; end of comment?
- je cmget13 ; e = yes, export cr
- mov noparse,1 ; still in comment
- jmp cmget01 ; read more chars
-
- ; read from tty device
- cmget10:mov ah,coninq ; Get a char from device, not file
- int dos ; with no echoing
- or al,al
- jnz cmget12 ; ignore null bytes of special keys
- int dos ; read and discard scan code byte
- jmp cmget10 ; try again
-
- cmget12:cmp al,'C'and 1Fh ; Control-C?
- je cmget14 ; e = yes
- cmp al,TAB ; tab is replaced by space
- jne cmget13 ; ne = not tab
- mov al,' '
- cmget13:ret ; normal exit, char is in AL
-
- cmget14:mov ah,prstr ; Control-C handler
- push dx
- mov dx,offset ctcmsg ; show Control-C
- int dos
- pop dx
- mov prevch,0
- mov flags.cxzflg,'C' ; tell others the news
- mov sp,cmdstk ; restore command entry stack pointer
- ret ; and fail immediately (a longjmp)
- cmgetc endp
-
- ; Read chars from user (cmgetc). Detect terminators. Reads from buffer
- ; comand.cmbuf. Set read pointer comand.cmrptr to next free buffer byte if
- ; char is not a terminator: chars CR, LF, FF, '?' (returns carry set for
- ; terminators). Do ^U, ^W editing, convert FF to CR plus clear screen.
- ; Edit "-<cr>" as line continuation, "\-<cr>" as "-<end of line>".
- ; Return char in AH.
- CMINBF proc near ; Buffer reader, final editor
- push di
- mov di,comand.cmwptr
- cmp di,offset comand.cmdbuf+size cmdbuf-3 ; max buffer size - 3
- pop di
- jb cminb1 ; b = not full
- mov ah,conout ; almost full, notify user
- push dx
- mov dl,bell
- int dos
- mov dx,offset comand.cmdbuf+size cmdbuf
- cmp comand.cmrptr,dx ; max buffer size?
- pop dx
- jb cminb1 ; b = more room
- mov ah,prstr
- push dx
- ; mov dx,offset cmer09 ; command too long
- mcmsg cmer09,ccmer09
- int dos
- pop dx
- jmp prserr ; overflow = parse error
-
- cminb1: push bx
- mov bx,comand.cmrptr
- mov ah,[bx] ; get current command char while here
- cmp bx,comand.cmwptr ; do we need to read more?
- pop bx ; no if cmrptr < cmwptr
- jb cminb2 ; b: cmrptr < cmwptr (have extra here)
- call cmgetc ; no readahead, read another into al
- mov ah,al ; keep char in 'ah'
- push bx
- mov bx,comand.cmwptr ; Get the pointer into the buffer
- mov [bx],ah ; Put it in the buffer
- inc bx
- mov comand.cmwptr,bx ; inc write pointer
- pop bx
- ; Char to be delivered is in ah
- cminb2: cmp ah,'W' and 1fh ; Is it a ^W?
- jne cminb3
- call cntrlw ; Kill the previous word
- jnc cminbf ; nc = no change, get another char
- jmp repars ; need a new command scan (cleans stk)
-
- cminb3: cmp ah,'U' and 1fh ; Is it a ^U?
- jne cminb3a ; ne = no
- mov comand.cmwptr,offset comand.cmdbuf ;reset buffer write pointer
- jmp repars ; Go start over (cleans stack)
- ; BS and DEL
- cminb3a:cmp ah,DEL ; Delete code?
- je cminb3b ; e = yes
- cmp ah,BS ; Backspace (a delete operator)?
- jne cminb4 ; ne = no
- cminb3b:call bufdel ; delete char from buffer
- jc cminb3c ; c = did erasure
- jmp cminbf ; no erasure, ignore BS, get more
- cminb3c:jmp repars ; could have deleted previous token
-
- cminb4: push bx ; look for hyphen or \hyphen
- cmp ah,cr ; check for hyphen line continuation
- jne cminb4b ; ne = not end of line
- mov bx,comand.cmwptr ; Get the pointer into the buffer
- cmp bx,offset comand.cmdbuf-2 ; do we have a previous char?
- jb cminb4b ; b = no
- cmp byte ptr[bx-2],'-' ; previous char was a hyphen?
- jne cminb4b ; ne = no
- pop bx
- call bufdel ; delete the hyphen
- jmp repars
- cminb4b:pop bx
- ; Echoing done here
- cmp comand.cmquiet,0 ; quiet mode?
- jne cminb5 ; yes, skip echoing
- cmp taklev,0 ; in a take file?
- je cminb4a ; e = no
- cmp flags.takflg,0 ; echo take file?
- je cminb5 ; e = no
- cminb4a:push ax ; save the char
- cmp ah,' ' ; printable?
- jae cminb4c ; yes, no translation needed
- cmp ah,cr ; this is printable
- je cminb4c
- cmp ah,lf
- je cminb4c
- cmp ah,escape ; escape?
- je cminb4d ; do not echo this character
- push ax ; show controls as caret char
- push dx
- mov dl,5eh ; caret
- mov ah,conout
- int dos
- pop dx
- pop ax
- add ah,'A'-1 ; make control code printable
- cminb4c:push dx
- mov dl,ah
- mov ah,conout
- int dos ; echo it ourselves
- pop dx
- cminb4d:pop ax ; and return char in ah
-
- cminb5: cmp ah,cr ; Is it a carriage return?
- je cminb6
- cmp ah,lf ; Is it a line feed?
- je cminb6
- cmp ah,ff ; Is it a formfeed?
- jne cminb7 ; none of the above, report bare char
- call cmblnk ; FF: clear the screen and
- push bx
- push cx
- push dx
- call locate ; Home the cursor
- mov bx,comand.cmwptr ; make the FF parse like a cr
- mov byte ptr [bx-1],cr ; pretend a carriage return were typed
- pop dx
- pop cx
- pop bx
- cminb6: cmp comand.cmwptr,offset comand.cmdbuf ; parsed any chars yet?
- jne cminb7 ; ne = yes
- cmp comand.cmcr,0 ; bare cr's allowed?
- jne cminb7 ; ne = yes
- jmp prserr ; If not, just start over
- cminb7: clc
- ret
- cminbf endp
-
- ; Read chars from cminbf. Comand.cmrptr points to next char to be read.
- ; Compresses repeated spaces if comand.cmsflg is non-zero. Exit with
- ; comand.cmrptr pointing at a terminator or otherwise at next free slot.
- ; Non-space then space acts as a terminator but comand.cmrptr is incremented.
- ; Substitution variables, '\%x', are detected and expanded. Return char in AH.
-
- CMGTCH proc near ; return char in AH, from rescan buf
- call cminbf ; get char from buffer or user
- push bx
- mov bx,comand.cmrptr ; get read pointer into the buffer
- mov ah,[bx] ; read the next char
- inc bx
- mov comand.cmrptr,bx ; where to read next time
- pop bx
- call subst ; examine for text substitution
- jnc cmgtc1 ; nc = no substitutions done
- jmp repars ; reparse line with new material
-
- cmgtc1: cmp ah,' ' ; Is it a space?
- jne cmgtc3 ; ne = no
- cmgtc2: cmp comand.cmsflg,0 ; space flag, was last char a space?
- jne cmgtch ; ne = yes, get another char
- mov comand.cmsflg,0FFH ; Set the space(s)-seen flag
- mov ah,' ' ; character for caller
- stc ; set carry for terminator
- ret ; return space as a terminator
- cmgtc3: mov comand.cmsflg,0 ; clear the space-seen flag
- cmp ah,escape ; terminators remain in buffer but
- je cmgtc4 ; are ready to be overwritten
- cmp ah,'?' ; Is the user curious?
- jne cmgtc3a ; ne = no
- cmp taklev,0 ; in a Take file?
- jne cmgtc3b ; ne = yes, make query ordinary char
- je cmgtc4
- cmgtc3a:cmp ah,cr
- je cmgtc4
- cmp ah,lf
- je cmgtc4
- cmp ah,ff
- je cmgtc4
- cmgtc3b:clc ; carry clear for non-terminator
- ret
- cmgtc4: dec comand.cmrptr ; point at terminating char
- stc ; set carry to say it is a terminator
- ret
- cmgtch endp
-
- ; Reset comand.cmdbuf write pointer (.cmwptr) to where the read pointer
- ; (.cmrptr) is now. Discards material not yet read.
- bufreset proc near
- push comand.cmrptr ; where next visible char is read
- pop comand.cmwptr ; where new char goes in buffer
- ret
- bufreset endp
-
- ; Delete character from screen and adjust buffer. Returns carry clear if
- ; no erasure, carry set otherwise.
- bufdel proc near
- dec comand.cmrptr ; remove previous char from buffer
- cmp comand.cmrptr,offset comand.cmdbuf ; back too far?
- jae bufde2 ; ae = no, material can be erased
- mov comand.cmrptr,offset comand.cmdbuf ; set to start of buffer
- call bufreset ; reset buffer
- clc ; say no erasure
- ret
- bufde2: call bufreset ; reset buffer
- stc ; say did erasure
- ret
- bufdel endp
-
- ; Come here is user types ^W when during input. Remove word from buffer.
- cntrlw proc near
- push ax
- push cx
- push dx
- mov cx,comand.cmrptr ; char beyond what user sees
- mov comand.cmwptr,cx ; truncate buffer there
- sub cx,offset comand.cmdbuf ; compute chars in buffer
- clc ; say have not yet modified line
- jcxz ctlw2 ; z = nothing to do, exit no-carry
- push es
- std ; scan backward
- mov ax,ds
- mov es,ax ; point to the data are
- mov di,comand.cmwptr ; looking from here
- dec di
- mov al,' '
- repe scasb ; look for non-space
- je ctlw1 ; all spaces, nothing to do
- inc di ; move back to non-space
- inc cx
- repne scasb ; look for a space
- jne ctlw1 ; no space, leave ptrs alone
- inc di
- inc cx ; skip back over space
- ctlw1: inc di
- pop es
- cld ; reset direction flag
- mov comand.cmwptr,di ; update pointer
- stc ; set carry to say modified line
- ctlw2: pop dx
- pop cx
- pop ax
- ret
- cntrlw endp
-
- ; Jump to REPARS to do a rescan of the existing buffer.
- ; Jump to PRSERR on a parsing error (quits command, clears old read material)
-
- PRSERR PROC NEAR
- mov comand.cmwptr,offset comand.cmdbuf ; initialize write pointer
- mov ah,prstr
- mov dx,offset crlf ; leave old line, start a new one
- int dos
- ; reparse current line
- REPARS: mov comand.cmrptr,offset comand.cmdbuf ; reinit read pointer
- mov comand.cmper,0 ; reset to variable recognition
- mov comand.cmsflg,0FFH ; strip leading spaces
- cmp taklev,0 ; in Take cmd?
- je prser2 ; e = no
- cmp flags.takflg,0 ; echo contents of Take file?
- je prser3 ; e = no
- prser2: call ctlu ; clear display's line, reuse it
- mov ah,prstr
- mov dx,comand.cmprmp ; display the prompt
- int dos
- prser3: mov bx,0ffffh ; returned keyword value
- mov sp,comand.cmostp ; set new sp to old one
- jmp comand.cmrprs ; jump to just before the prompt call
- PRSERR ENDP
-
- ; This routine prints the prompt and specifies the reparse address.
- ; Enter with pointer to prompt string in dx.
- PROMPT PROC NEAR
- mov comand.cmprmp,dx ; save the prompt
- pop ax ; Get the return address
- mov comand.cmrprs,ax ; Save as address to go to on reparse
- mov comand.cmostp,sp ; Save for later restoration
- push ax ; Put it on the stack again
- mov ax,offset comand.cmdbuf
- mov comand.cmwptr,ax ; reset buffer read/write pointers
- mov comand.cmrptr,ax
- mov ax,0
- mov comand.cmper,0 ; allow substitutions
- mov comand.cmsflg,0FFH ; remove leading spaces
- cmp flags.takflg,0 ; look at Take flag
- jne promp1 ; ne=supposed to echo, skip this check
- cmp taklev,0 ; inside a take file?
- je promp1 ; no, keep going
- ret ; yes, return
- promp1: mov ah,prstr
- mov dx,offset crlf
- int dos
- mov ah,prstr ; display the prompt
- mov dx,comand.cmprmp
- int dos
- ret
- PROMPT ENDP
-
- ISDEV PROC NEAR ; Set carry if STDIN is non-disk
- push ax
- push bx
- push dx
- mov al,0 ; get device info
- mov ah,ioctl
- mov bx,0 ; handle 0 is stdin
- int dos
- and dl,80h ; bit set if handle is for a device
- rcl dl,1 ; put it into the carry bit
- pop dx
- pop bx
- pop ax
- ret ; carry set if device
- ISDEV ENDP
-
- ISEOF PROC NEAR ; Set carry if STDIN is at EOF
- push ax ; but only if stdin is a non-device
- push bx
- push dx
- mov al,0 ; get device info
- mov ah,ioctl
- mov bx,0 ; handle 0 is stdin
- int dos
- test dl,80h ; bit set if handle is for a device
- mov ah,ioctl
- mov al,6 ; get handle input status, set al
- jnz iseof1 ; nz = device, always ready (al != 0)
- int dos
- iseof1: or al,al ; EOF?
- pop dx
- pop bx
- pop ax
- jnz iseof2 ; nz = no
- stc ; set carry for eof
- ret
- iseof2: clc ; clear carry for not-eof
- ret
- ISEOF ENDP
- ; Convert ascii characters in al and ah to lowercase. [jrd]
- ; All registers are preserved except AX, of course.
-
- TOLOWR PROC NEAR
- cmp ah,'A' ; less that cap A?
- jl tolow1 ; l = yes. leave untouched
- cmp ah,'Z'+1 ; more than cap Z?
- jns tolow1 ; ns = yes
- or ah,20H ; convert to lowercase
- tolow1: cmp al,'A' ; less that cap A?
- jl tolow2 ; l = yes. leave untouched
- cmp al,'Z'+1 ; more than cap Z?
- jns tolow2 ; ns = yes
- or al,20H ; convert to lowercase
- tolow2: ret
- TOLOWR endp
-
- ; Jumping to this location is like retskp. It assumes the instruction
- ; after the call is a jmp addr.
-
- RSKP PROC NEAR
- pop bp
- add bp,3
- push bp
- ret
- RSKP ENDP
-
- ; Jumping here is the same as a ret.
-
- R PROC NEAR
- ret
- R ENDP
-
- code ends
- end
-